Skip to content

[test-84/e2e] E2E 테스트 안정화 및 회귀 수정 - #216

Merged
hm1n merged 3 commits into
developfrom
hm1n/test-84-e2e-e2e
Sep 8, 2026
Merged

[test-84/e2e] E2E 테스트 안정화 및 회귀 수정#216
hm1n merged 3 commits into
developfrom
hm1n/test-84-e2e-e2e

Conversation

@hm1n

@hm1n hm1n commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

같은 커밋으로 CI를 20회 반복 실행해 E2E 16건의 케이스별 실패율을 측정했습니다.
측정 결과를 근거로 CI의 retries를 2회에서 1회로 정했습니다.
측정 전용으로 넣었던 설정은 모두 되돌렸습니다.
Closes #215


Why

왜 이 작업을 진행했나요?

CI의 retries가 2회로 되어 있었는데 관측 없이 정한 값이었습니다. 케이스별 실패율을 모르니 2회가 적절한지 판단할 근거가 없었습니다.

재시도 횟수는 두 방향으로 손해를 냅니다. 너무 적으면 일회성 오류가 실패로 남고, 너무 많으면 진짜 회귀의 실패 확정이 늦어집니다. 그래서 값을 정하기 전에 실제 흔들림 크기를 먼저 재기로 했습니다.


Decision

어떤 구현 방식을 선택했나요?

retries: process.env.CI ? 1 : 0으로 정했습니다. 로컬은 기존과 같이 0회이며 실행 방식을 바꾸지 않습니다.

측정은 이 PR의 실행을 gh run rerun으로 반복했습니다. 재실행은 커밋 SHA가 그대로라 같은 커밋 조건을 정확히 만족합니다. develop에 트리거를 추가하지 않아도 됩니다.

  • 대상 커밋: 49c01fb
  • 워크플로 실행: run 33605863639, attempt 1~20
  • 뷰포트: mobile. base가 develop이라 matrix가 mobile 단일로 분기합니다
  • 실행 시각: attempt 118은 2026-09-02 07:5309:03 UTC, attempt 1920은 2026-09-03 01:1401:17 UTC

집계는 각 attempt의 job 로그에서 가져왔습니다. 전체 재실행은 이전 attempt의 아티팩트를 지우므로 json reporter 파일은 마지막 attempt 것만 남습니다. attempt별 로그는 그대로 남아 있어 이쪽으로 집계했습니다.

실행 단위 측정 결과

항목
실행 횟수 20
실행 성공 19
실행 실패 1 (attempt 19)
실행 단위 실패율 5.0%
케이스 실행 총계 320 (16건 × 20회)
케이스 단위 실패 1
케이스 단위 실패율 0.31%
스위트 소요 시간 33.7s ~ 56.8s (중앙값 약 45s)

케이스별 실패율

# 케이스 실패 / 실행 실패율
1 auth.spec.ts:7 접근 제어 › 비로그인 사용자가 보호 경로를 열면 첫 화면으로 이동한다 0 / 20 0%
2 auth.spec.ts:23 로그인 콜백 처리 › 약관에 동의한 사용자는 인증 콜백 뒤 요청한 초대 경로로 이동한다 1 / 20 5%
3 group.spec.ts:31 그룹 생성 › 필수 정보를 입력하면 그룹 미리보기로 이동한다 0 / 20 0%
4 group.spec.ts:59 그룹 생성 › 금액과 인원을 바꾸면 나눈 금액이 반올림되어 갱신된다 0 / 20 0%
5 group.spec.ts:76 그룹 생성 › 미리보기에서 그룹을 만들면 홈으로 이동한다 0 / 20 0%
6 group.spec.ts:111 홈 그룹 조회와 상세 진입 › 홈의 그룹 카드를 누르면 그룹 정보 탭으로 진입한다 0 / 20 0%
7 group.spec.ts:146 참여자 권한과 그룹 탈퇴 › 일반 참여자는 그룹을 수정할 수 없고 나가기만 선택할 수 있다 0 / 20 0%
8 invite.spec.ts:31 초대 링크 조회 › 유효한 대기 중 초대 링크에서 초대 정보를 확인할 수 있다 0 / 20 0%
9 invite.spec.ts:58 초대 응답 › 초대 대상자가 수락하면 엔빵 참여가 완료된다 0 / 20 0%
10 landing.spec.ts:3 랜딩 페이지의 주요 콘텐츠를 노출한다 0 / 20 0%
11 settlement.spec.ts:53 납부 상태 변경 › 그룹장이 참여자의 납부 상태를 완료로 변경한다 0 / 20 0%
12 settlement.spec.ts:80 납부 상태 변경 › 일반 참여자가 자신의 납부 상태를 완료로 변경한다 0 / 20 0%
13 settlement.spec.ts:113 납부 상태 변경 › 일반 참여자는 다른 참여자의 납부 상태를 변경할 수 없다 0 / 20 0%
14 settlement.spec.ts:141 정산 기간 기록 조회 › 현재 정산 기간의 납부 기록만 참여자 목록에 반영된다 0 / 20 0%
15 settlement.spec.ts:165 정산 기간 기록 조회 › 새 참여자가 추가되면 그룹 시작일 기준의 미납 기록이 한 건 생성된다 0 / 20 0%
16 settlement.spec.ts:190 납부 상태 저장 처리 › 납부 상태 저장에 실패하면 화면 상태를 유지하고 오류를 알린다 0 / 20 0%

#209에서 확인했던 테스트 계정 tag 충돌은 20회 동안 한 번도 재현되지 않았습니다. 3dc3ada의 재시도 처리가 동작하는 것으로 보입니다.

1회로 정한 이유

  • 케이스 실패율 0.31%짜리 일회성 오류는 한 번의 재시도로 걸러집니다.
  • 반복해서 깨지는 테스트는 그대로 실패로 남습니다.
  • 기존 값 2회는 관측된 흔들림 크기에 비해 과하고, 진짜 회귀의 실패 확정만 늦춥니다.

검토한 대안

검토한 대안 설명 선택하지 않은 이유
workflow_dispatch 워크플로를 수동 실행으로 20회 돌립니다. default branch인 develop에 트리거가 있어야 동작해 제약과 부딪힙니다
seeder 재시도 seeder에 PGRST303 전용 재시도를 넣습니다. 320회 중 1회이고 재현되지 않아 근거가 약합니다

Changes

무엇이 변경되었나요?

Fix

  • playwright.config.tsretriesprocess.env.CI ? 1 : 0으로 바꿨습니다. CI가 2회에서 1회가 됩니다.

Test

  • 측정 전용으로 넣었던 retries: 0json reporter, 산출물 업로드 if: always()를 모두 되돌렸습니다.

Trade-off

한계와 트레이드오프

  • 재시도로 통과한 건은 Playwright가 flaky로 따로 집계하므로 관측은 계속됩니다. PGRST303이 flaky로 반복해서 뜨면 그때 근거를 갖고 seeder 재시도를 넣습니다.
  • attempt 19의 trace와 스크린샷은 남아 있지 않습니다. 전체 재실행이 이전 attempt의 아티팩트를 지웠기 때문입니다. 원인 판단은 job 로그만 근거로 합니다.
  • PC 뷰포트 matrix는 이번에 확인하지 못했습니다. 이 PR은 base가 develop이라 matrix가 mobile 단일로 분기합니다. main 대상 PR에서만 확인할 수 있어 다음 릴리즈 PR에서 봐야 합니다.

Impact

기존 기능에 미치는 영향

  • develop 대비 남는 변경은 playwright.config.ts의 한 줄입니다.
  • CI에서 재시도가 한 번으로 줄어듭니다. 두 번 이상 깨지던 테스트는 이제 실패로 확정됩니다.
  • 로컬 실행은 바뀌지 않습니다.
  • 제품 코드 변경은 없습니다.

Edge Cases

Edge Case 및 실패 시나리오

attempt 19에서 케이스 하나가 실패했습니다.

1) [mobile] › e2e/auth.spec.ts:23:7 › 로그인 콜백 처리 › 약관에 동의한 사용자는 인증 콜백 뒤 요청한 초대 경로로 이동한다

    {
      code: 'PGRST303',
      details: null,
      hint: null,
      message: 'JWT issued at future'
    }

PostgREST가 요청에 담긴 토큰의 iat를 자기 시계보다 미래로 판단해 거절했습니다.

실패 지점은 브라우저가 아니라 테스트 준비 단계의 Node 코드입니다. 오류 출력에 stack이 없다는 것은 Error가 아닌 plain object가 던져졌다는 뜻이고, supabase-js의 PostgrestError가 그 형태입니다. e2e/fixtures/seed.ts에서 this.admin으로 PostgREST를 호출한 뒤 throw error 하는 지점들이 여기 해당합니다.

그래서 createSession이 만드는 사용자 세션 토큰과는 무관합니다. 토큰을 발급하고 iat를 검증하는 일은 모두 Supabase에서 일어나며 우리 코드는 이 시각에 관여하지 않습니다. 원인을 환경으로 분류했습니다. 같은 커밋의 다른 19회에서는 재현되지 않았습니다.

retries가 이 실패 유형을 걸러냅니다. 재시도는 fixture teardown을 attempt마다 실행하므로 잔여 데이터도 남지 않습니다.


Review Points

리뷰어가 집중해서 봐야 할 부분

🔴 High

  • retries를 1회로 정한 판단을 확인해 주세요. 케이스 단위 실패율 0.31%를 근거로 삼았습니다.

🟡 Medium

  • PGRST303을 코드로 대응하지 않고 재시도로 넘긴 결정을 확인해 주세요. 320회 중 1회이고 원인이 Supabase에 있어 지금은 근거가 약하다고 판단했습니다.

🟢 Low

  • 측정 전용 설정이 모두 되돌아갔는지 확인해 주세요.

Validation

어떻게 검증했나요?

  • 단위 테스트
  • E2E 테스트
  • 수동 테스트
  • lint
  • typecheck

실행 결과

  • 같은 커밋으로 20회 반복 실행했습니다. 실행 19회 성공, 1회 실패입니다. 케이스 단위로는 320회 중 1회 실패입니다.
  • 산출물 업로드를 확인했습니다. attempt 20에서 playwright-mobile-20 아티팩트가 성공 실행에도 올라왔고, 실패 시 업로드는 attempt 19에서 동작을 확인했습니다.

#215 Task 8. 같은 커밋으로 CI를 반복 실행해 케이스별 실패율을 측정하기 위한
측정 전용 설정이다. 측정이 끝나면 retries 최종값을 정하고 함께 정리한다.

- retries를 0으로 둔다. 재시도가 성공하면 결과가 초록으로 끝나 흔들림이
  드러나지 않으므로 측정 기간에는 재시도를 꺼야 데이터가 나온다.
- json reporter를 추가한다. 케이스별 실패율을 세려면 통과한 실행의 결과도
  파일로 남아야 한다.
- 산출물 업로드 조건을 always로 바꾼다. 같은 이유로 성공한 실행의 리포트도
  받아야 한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
nbread Ready Ready Preview Sep 3, 2026 2:36am UTC

hm1n and others added 2 commits September 3, 2026 11:34
#215 Task 8. 같은 커밋으로 20회 반복 실행하는 측정이 끝나 측정 전용 설정을
모두 원래대로 돌린다. `develop`에 남기지 않기로 한 설정들이다.

- retries를 측정 전 값으로 되돌린다. 최종값은 다음 커밋에서 정한다.
- json reporter를 뺀다. 케이스별 집계가 끝나 더 필요하지 않다.
- 산출물 업로드 조건을 failure로 되돌린다. 성공한 실행의 리포트는
  측정 기간에만 필요했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#215 Task 8. 같은 커밋(49c01fb)으로 CI를 20회 반복 실행해 재시도 없이 측정한
결과를 근거로 값을 정한다.

측정값은 케이스 실행 320회(16건 x 20회) 중 실패 1회로 케이스 실패율 0.31%,
실행 단위로는 20회 중 1회 실패다. 유일한 실패는 seeder가 PostgREST를 호출할 때
받은 `PGRST303 JWT issued at future`로, 토큰 발급과 검증이 모두 Supabase 쪽에서
일어나는 구간이라 우리 코드가 시각에 관여하지 않는다.

1회로 정한 이유는 이 정도 일회성 오류는 한 번의 재시도로 흡수되고, 반복해서
깨지는 테스트는 그대로 실패로 남기 때문이다. 2회는 관측된 흔들림 크기에 비해
과하고 진짜 회귀의 실패 확정만 늦춘다. 재시도로 통과한 건은 리포트에 flaky로
따로 집계되므로 흔들림 관측은 계속 가능하다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@hm1n
hm1n marked this pull request as ready for review September 3, 2026 03:17
@hm1n

hm1n commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 49cb9368f1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@hm1n hm1n self-assigned this Sep 8, 2026
@hm1n hm1n added the 🧪 Test 테스트 코드 작성 및 테스트 환경 label Sep 8, 2026
@hm1n
hm1n merged commit 07d6ebe into develop Sep 8, 2026
4 checks passed
@hm1n
hm1n deleted the hm1n/test-84-e2e-e2e branch September 8, 2026 02:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🧪 Test 테스트 코드 작성 및 테스트 환경

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[test-84/e2e] E2E 테스트 안정화 및 회귀 수정

1 participant